package com.cloudwise.servlet;

import com.cloudwise.annotation.MyController;
import com.cloudwise.annotation.MyRequestMapping;
import org.reflections.Reflections;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author ：Teacher陈
 * @date ：Created in 2021/2/22 10:55
 * @description：前端控制器
 * @modified By：
 * @version: 1.0
 */
public class MyDispatcherServlet extends HttpServlet {
    /**
     * 配置扫描的包
     */
    private Properties properties = new Properties();
    /**
     * 封装所有的controller类
     */
    private Set<Class<?>> classSet = new HashSet<>();
    /**
     * springmvc容器
     */
    private Map<String, Object> springMVCContext = new HashMap<>();
    /**
     * 映射处理器
     */
    private Map<String, Method> handlerMapping = new HashMap<>();

    /**
     * 后端处理器的映射关系
     */
    private Map<String, Object> controllerMap = new HashMap<>();

    /**
     * @param config
     * @return
     * @create by: Teacher陈
     * @description: 初始化方法
     * @create time: 2021/2/22 10:59
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        String initParameter = config.getInitParameter("contextConfigLocation");
        //加载配置文件
        loadConfigfile(initParameter);
        //扫描controller包
        scanPackage(properties.getProperty("package"));
        //初始化controller
        initController();
        //初始化处理器映射器
        initHandlerMapping();

    }

    /**
     * @param req resp
     * @create by: Teacher陈
     * @description: 业务处理方法
     * @create time: 2021/2/22 10:59
     */
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //处理请求
        if(handlerMapping.isEmpty()){
            return;
        }
        //获取url
        String uri = req.getRequestURI();
        String contextPath = req.getContextPath();
        String url = uri.replace(contextPath, "");
        if(!handlerMapping.containsKey(url)){
            resp.getWriter().println("404");
        }else
        {
            Method method = handlerMapping.get(url);
            Object controller= controllerMap.get(url);
            try {
                method.invoke(controller);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

    }

    public void loadConfigfile(String fileName) {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(fileName);
        try {
            properties.load(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                resourceAsStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @param packageName
     * @create by: Teacher陈
     * @description: 扫描所有带mycontroller注解的类
     * @create time: 2021/2/22 11:21
     */
    public void scanPackage(String packageName) {
        Reflections reflections = new Reflections(packageName);
        classSet = reflections.getTypesAnnotatedWith(MyController.class);
    }

    /**
     * @create by: Teacher陈
     * @description: 初始化controller
     * @create time: 2021/2/22 11:23
     */
    public void initController() {
        if (classSet.isEmpty()) {
            return;
        }
        for (Class<?> controller : classSet) {
            try {
                //controller.getSimpleName()获取类名,首字母转小写
                springMVCContext.put(tolowerFirstWord(controller.getSimpleName()),controller.newInstance());

            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
    public  void initHandlerMapping(){
        if(springMVCContext.isEmpty()){
            return ;
        }
        for (Map.Entry<String, Object> entry : springMVCContext.entrySet()) {
            Class<?> aClass = entry.getValue().getClass();
            if(!aClass.isAnnotationPresent(MyController.class)){
                continue;
            }else{
                //controller类上的requestmapping值
                String baseUrl="";
                if(aClass.isAnnotationPresent(MyRequestMapping.class)){
                    //如果类包含注解MyRequestMapping，获取注解值
                    MyRequestMapping annotation = aClass.getAnnotation(MyRequestMapping.class);
                    baseUrl = annotation.value();
                }
                //获取所有的方法
                Method[] methods = aClass.getMethods();
                for (Method method : methods) {
                    //判断方法上含有MyRequestMapping注解
                    if(method.isAnnotationPresent(MyRequestMapping.class)){
                        MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class);
                        String url = annotation.value();
                        url=baseUrl+url;
                        handlerMapping.put(url,method);
                        try {
                            controllerMap.put(url,aClass.newInstance());
                        } catch (InstantiationException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }

                }

            }
        }
    }
    /**
     * @create by: Teacher陈
     * @description: 首字母转小写
     * @create time: 2021/2/22 11:28
     * @param word
     * @return String
     */
    public   String  tolowerFirstWord(String word){
        char[] array = word.toCharArray();
        array[0]+=32;
        return   String.valueOf(array);
    }


}
